2.2. Configuring a Web Service Client to Acquire and Send SAML Tokens
In this section, you see the client application that acquires a SAML token from LocalSTS and sends it to ACS. Listing 13 shows the code in the main function of the Program.cs file from the Client project.
Example 13. Program.cs in Client Project
private const string ServiceNamespace = "proazure-1"; private const string AcsHostName = "accesscontrol.windows.net"; private const string StsBaseAddress = "localhost/localsts"; private const string StsPath = "Trust/13/UserName"; public static void Main(string[] args) { string stsAddress = string.Format("https://{0}/{1}", StsBaseAddress, StsPath); string acsSTSAddress = string.Format ("https://{0}.{1}/WRAPv0.8", ServiceNamespace, AcsHostName); string samlAssertion = GetSamlAssertion(stsAddress, acsSTSAddress); string acsToken = GetACSToken(samlAssertion);
// create the binding and address to communicate with the service WebHttpBinding binding = new WebHttpBinding(WebHttpSecurityMode.None); Uri address = new Uri(@"http://localhost/acsexample");
WebChannelFactory<IACSExample> channelFactory = new WebChannelFactory<IACSExample>(binding, address);
IACSExample proxy = channelFactory.CreateChannel();
using (new OperationContextScope(proxy as IContextChannel)) { string authHeaderValue = "WRAPv0.8" + " " + HttpUtility.UrlDecode(acsToken);
WebOperationContext.Current.OutgoingRequest.Headers .Add("authorization", authHeaderValue);
// call the service and get a response try { Console.Write("\tCalling GetMachineName: "); Console.WriteLine("Machine Name is:" + proxy.GetMachineName());
Console.Write("\tCalling GetUserDomainName: "); Console.WriteLine("User Domain Name is:" + proxy.GetUserDomainName());
Console.Write("\tCalling GetOSVersion: "); Console.WriteLine("OS Version is:" + proxy.GetOSVersion()); Console.Write("\tCalling EncodeString: "); Console.WriteLine("Encoded String is:" + Encoding.UTF8.GetString(proxy.EncodeString("Welcome to ProAzure."))); } catch (MessageSecurityException ex) { if (ex.InnerException != null) { WebException wex = ex.InnerException as WebException; if (wex != null) { Console.WriteLine("Error: {0}", wex.Message); } } else { throw; } } }
((IClientChannel)proxy).Close();
channelFactory.Close();
Console.ReadLine(); }
|
The GetSamlAssertion()
function retrieves the SAML token from LocalSTS, and GetACSToken()
sends the SAML token to ACS and returns an ACS token. Listing 14 shows the code for the GetSamlAssertion() and GetACSToken() functions.
Example 14. GetSamlAssertion and GetACSToken
private static string GetSamlAssertion(string stsAddress, string acsStsAddress) { WSTrustChannelFactory trustChannelFactory = new WSTrustChannelFactory( new WindowsWSTrustBinding (SecurityMode.TransportWithMessageCredential), new EndpointAddress(new Uri(stsAddress))); trustChannelFactory.TrustVersion = TrustVersion.WSTrust13;
RequestSecurityToken rst = new RequestSecurityToken(WSTrust13Constants.RequestTypes.Issue, WSTrust13Constants.KeyTypes.Bearer); rst.AppliesTo = new EndpointAddress(acsStsAddress); rst.TokenType = Microsoft.IdentityModel.Tokens. SecurityTokenTypes.Saml2TokenProfile11;
WSTrustChannel channel = (WSTrustChannel)trustChannelFactory.CreateChannel(); GenericXmlSecurityToken token = channel.Issue(rst) as GenericXmlSecurityToken;
return token.TokenXml.OuterXml; }
private static string GetACSToken(string samlAssertion) { WebClient tokenClient = new WebClient(); tokenClient.BaseAddress = string.Format("https://{0}.{1}", ServiceNamespace, AcsHostName);
NameValueCollection values = new NameValueCollection(); values.Add("wrap_SAML", samlAssertion); values.Add("applies_to", "http://localhost/acsexample");
byte[] responseBytes = tokenClient.UploadValues("WRAPv0.8", values); string response = Encoding.UTF8.GetString(responseBytes);
return response .Split('&') .Single(value => value.StartsWith ("wrap_token=", StringComparison.OrdinalIgnoreCase)) .Split('=')[1]; }
|
To run the example, do the following:
Run the client from the ACSwithSAML solution folder.